package com.ldoublem.flightseatselect;

import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.agp.window.dialog.ToastDialog;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.global.resource.*;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.ManipulationEvent;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;

/**
 * Created by lumingmin on 16/7/22.
 */
public class FlightSeatView extends Component implements Component.DrawTask, Component.BindStateChangedListener {
    private static final String TAG = "FlightSeatView";

    private Paint mPaint;
    private Paint mPaintOther;
    private Paint mPaintMap;

    private RectFloat rectFCabin;
    RectFloat rectFWall;
    RectFloat rectFWC;

    private HashMap<String, RectFloat> mSeats = new HashMap<>();
    private HashMap<String, SeatState> mSeatSelecting = new HashMap<>();
    private HashMap<String, SeatState> mSeatSelected = new HashMap<>();
    private HashMap<String, RectFloat> mSeatSelectingRectF = new HashMap<>();

    private Path pathFuselage;
    private Path pathArrow;
    private Path pathTail;

    PixelMap mBitmapCabin = null;
    PixelMap mBitmapFuselage = null;
    PixelMap mBitmapArrow = null;
    PixelMap mBitmapTail = null;
    PixelMap mBitmapSeat_normal = null;
    PixelMap mBitmapSeat_selected = null;
    PixelMap mBitmapSeat_selecting = null;

    float scaleValue = 2.0f;
    float scaleMaxValue = 3f;
    float scaleMap = 10f;
    float moveY = 0;

    private int maxSelectStates = 10;

    private String getSeatKeyName(int row, int column) {
        return String.valueOf(row + "#" + column);
    }

    public void setSeatSelected(int row, int column) {
        mSeatSelected.put(getSeatKeyName(row, column), SeatState.Selected);
    }

    public void goCabinPosition(CabinPosition mCabinPosition) {
        if (mAnimatedValue > 0) {
            if (mCabinPosition == CabinPosition.Top) {
                moveY = 0;
            } else if (mCabinPosition == CabinPosition.Last) {
                moveY = rectFCabin.getHeight() - rectFCabin.getWidth() * 2.5f;
            } else if (mCabinPosition == CabinPosition.Middle) {
                moveY = (rectFCabin.getHeight() - rectFCabin.getWidth() * 2.5f) / 2;
            }
            invalidate();
        }
    }

    public void setEmptySelecting() {
        mSeatSelecting.clear();
        mSeatSelectingRectF.clear();
        invalidate();
    }

    public void setMaxSelectStates(int count) {
        maxSelectStates = count;
    }

    public FlightSeatView(Context context) {
        this(context, null);
    }

    public FlightSeatView(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    public FlightSeatView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
        addDrawTask(this);
    }

    private int dip2px(float dpValue) {
        Optional<Display> display = DisplayManager.getInstance().getDefaultDisplay(getContext());
        final float scale = display.get().getAttributes().densityPixels;
        return (int) (dpValue * scale + 0.5f);
    }

    @Override
    public void estimateSize(int widthEstimatedConfig, int heightEstimatedConfig) {
        super.estimateSize(widthEstimatedConfig, heightEstimatedConfig);
        int widthSpecMode = MeasureSpec.getMode(widthEstimatedConfig);
        int widthSpecSize = MeasureSpec.getSize(widthEstimatedConfig);
        int heightSpecMode = MeasureSpec.getMode(heightEstimatedConfig);
        int heightSpecSize = MeasureSpec.getSize(heightEstimatedConfig);
        if (widthSpecMode == MeasureSpec.NOT_EXCEED
            && heightSpecMode == MeasureSpec.NOT_EXCEED) {
            setEstimatedSize(dip2px(150), 200);
        } else if (widthSpecMode == MeasureSpec.NOT_EXCEED) {
            setEstimatedSize((int) (heightSpecSize * 0.75f), heightSpecSize);
        } else if (heightSpecMode == MeasureSpec.NOT_EXCEED) {
            setEstimatedSize(widthSpecSize, (int) (widthSpecSize / 0.75f));
        }
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL_STYLE);

        mPaintOther = new Paint();
        mPaintOther.setAntiAlias(true);
        mPaintOther.setColor(new Color(Color.rgb(138, 138, 138)));
        mPaintOther.setStyle(Paint.Style.FILL_STYLE);

        mPaintMap = new Paint();
        mPaintMap.setAntiAlias(true);
        mPaintMap.setColor(new Color(Color.rgb(138, 138, 138)));
        mPaintMap.setStyle(Paint.Style.FILL_STYLE);

        rectFCabin = new RectFloat();
        rectFWall = new RectFloat();
        rectFWC = new RectFloat();

        pathFuselage = new Path();
        pathFuselage.reset();
        pathArrow = new Path();
        pathArrow.reset();
        pathTail = new Path();
        pathTail.reset();
    }

    public void setTouchListener(AbilitySlice context){
        setTouchEventListener(new MoveListerner(context) {
            @Override
            public void moveDirection(Component v, int direction, float distanceX, float distanceY) {}

            @Override
            public void moveUpAndDownDistance(ManipulationEvent event, int distance, int distanceY) {
                if (mAnimatedValue > 0) {
                    if (moveY >= 0 && moveY <= rectFCabin.getHeight() - rectFCabin.getWidth() * 2.5f) {
                        moveY = moveY + distanceY;
                        invalidate();
                    }
                    if (moveY < 0) {
                        moveY = 0;
                    }
                    if (moveY > rectFCabin.getHeight() - rectFCabin.getWidth() * 2.5f) {
                        moveY = rectFCabin.getHeight() - rectFCabin.getWidth() * 2.5f;
                    }
                }
            }

            @Override
            public void moveOver() {}

            @Override
            public void Touch(float x, float y) {
                if (mAnimatedValue == 0) {
                    startAnim(true);
                } else {
                    RectFloat selecting = new RectFloat();
                    Iterator iter = mSeats.entrySet().iterator();
                    while (iter.hasNext()) {
                        Map.Entry entry = (Map.Entry) iter.next();
                        String key = (String) entry.getKey();
                        RectFloat val = (RectFloat) entry.getValue();
                        if (val.isInclude(x, y)) {
                            if (mSeatSelecting.containsKey(key)) {
                                if (mSeatSelecting.get(key) != SeatState.Selected) {
                                    mSeatSelecting.remove(key);
                                    mSeatSelectingRectF.remove(key);
                                    invalidate();
                                }
                            } else {
                                if (mSeatSelecting.size()
                                        >= maxSelectStates) {
                                    ToastDialog toastDialog = new ToastDialog(getContext());
                                    toastDialog.setText("Choose a maximum of " + maxSelectStates);
                                    toastDialog.show();
                                    return;
                                } else {
                                    if (!mSeatSelected.containsKey(key)) {
                                        mSeatSelecting.put(key,
                                                SeatState.Selecting);
                                        selecting.top = val.top / scaleMap
                                                + rectFCabin.top + rectFCabin.getWidth() * 0.8f
                                                + moveY / scaleMap;
                                        selecting.bottom = val.bottom / scaleMap
                                                + rectFCabin.top + rectFCabin.getWidth() * 0.8f
                                                + moveY / scaleMap;
                                        selecting.left = val.getCenter().getPointX() / scaleMap - val.getWidth() / scaleMap / 2f
                                                - val.getWidth() / scaleMap / 2f
                                                + rectFCabin.left;
                                        selecting.right = val.getCenter().getPointX() / scaleMap + val.getWidth() / scaleMap / 2f
                                                - val.getWidth() / scaleMap / 2f
                                                + rectFCabin.left;

                                        mSeatSelectingRectF.put(key, selecting);
                                        invalidate();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        });
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.save();
        scaleValue = scaleMaxValue * mAnimatedValue;
        Matrix matrix = new Matrix();
        matrix.postScale(1 + scaleValue * 2f, 1 + scaleValue * 2f);
        matrix.postTranslate(getWidth() * -1 * scaleValue,
            scaleValue * 2f * (getHeight() / 3f / 3f + getWidth() / 8f) * -1 - moveY);
        float rectFCabinWidth = getWidth() / 8f;
        rectFCabin.top = getHeight() / 3f / 3f;
        rectFCabin.left = getWidth() / 2f - rectFCabinWidth / 2f;
        rectFCabin.right = getWidth() / 2f + rectFCabinWidth / 2f;
        rectFCabin.bottom = getHeight() / 3f / 3f + getHeight() / 3f * 2f;

        canvas.drawPixelMapHolder(new PixelMapHolder(getBitmapFuselage(rectFCabinWidth)), getLeft(), getTop(), mPaint);
        canvas.drawPixelMapHolder(new PixelMapHolder(getBitmapArrow()), getLeft(), getTop(), mPaint);
        canvas.drawPixelMapHolder(new PixelMapHolder(getBitmapTail()), getLeft(), getTop(), mPaint);
        canvas.drawPixelMapHolder(new PixelMapHolder(getBitmapCabin()), getLeft(), getTop(), mPaint);
        rectFCabinWidth = getWidth() / 8f * (1 + scaleValue * 2f);
        rectFCabin.top = getHeight() / 3f / 3f;
        rectFCabin.left = getWidth() / 2f - rectFCabinWidth / 2f;
        rectFCabin.right = getWidth() / 2f + rectFCabinWidth / 2f;
        rectFCabin.bottom = getHeight() / 3f / 3f + getHeight() / 3f * 2f * (1 + scaleValue * 2f);
        canvas.translate(0,
            scaleValue * (1 - 0.1f * (scaleMaxValue - 2))
                * (getHeight() / 3f / 3f + getWidth() / 8f) * -1 - moveY);
        drawSeatFirst(canvas);
        drawSeatTourist(canvas);
        drawSeatLast(canvas);
        drawSeatMap(canvas);
        canvas.restore();
    }

    public enum CabinPosition {
        Top, Middle, Last
    }

    enum SeatType {
        Left, Middle, Right
    }

    enum SeatState {
        Normal, Selected, Selecting
    }

    enum CabinType {
        Frist, Second, Tourist, Last
    }

    private void setSeat(int i, int j, Canvas canvas, float seatWH, SeatType type, CabinType cabinType) {
        float top = 0f;
        float left = 0f;
        if (cabinType == CabinType.Frist) {
            if (type == SeatType.Left) {
                top = rectFCabin.top + rectFCabin.getWidth() / 2 + seatWH + i * (seatWH) + seatWH / 2;
                left = rectFCabin.left + j * (seatWH) + seatWH / 3;
            } else if (type == SeatType.Middle) {
                top = rectFCabin.top + rectFCabin.getWidth() / 2 + seatWH + i * (seatWH) + seatWH / 2 + seatWH / 2;
                left = rectFCabin.left + j * (seatWH) + seatWH * 1f;
            } else if (type == SeatType.Right) {
                top = rectFCabin.top + rectFCabin.getWidth() / 2 + seatWH + i * (seatWH) + seatWH / 2;
                left = rectFCabin.left + j * (seatWH) + seatWH * 2f - seatWH / 3f;
            }
        } else if (cabinType == CabinType.Second) {
            if (type == SeatType.Left) {
                left = rectFCabin.left + j * (seatWH) + seatWH / 3;
                top = rectFCabin.top + seatWH * 14f + rectFCabin.getWidth() / 2 + seatWH + i * (seatWH) + seatWH / 2;
            } else if (type == SeatType.Middle) {
                left = rectFCabin.left + j * (seatWH) + seatWH / 1f;
                top = rectFCabin.top + rectFCabin.getWidth() / 2 + seatWH * 14f + seatWH + i * (seatWH) + seatWH / 2 + seatWH / 2;
            } else if (type == SeatType.Right) {
                left = rectFCabin.left + j * (seatWH) + seatWH * 2f - seatWH / 3f;
                top = rectFCabin.top + seatWH * 14f + rectFCabin.getWidth() / 2 + seatWH + i * (seatWH) + seatWH / 2;
            }
        } else if (cabinType == CabinType.Tourist) {
            if (type == SeatType.Left) {
                left = rectFCabin.left + j * (seatWH) + seatWH / 3;
                top = rectFWall.bottom + seatWH * 1.5f + i * (seatWH);
            } else if (type == SeatType.Middle) {
                left = rectFCabin.left + j * (seatWH) + seatWH * 1f;
                top = rectFWall.bottom + seatWH * 1.5f + i * (seatWH);
            } else if (type == SeatType.Right) {
                left = rectFCabin.left + j * (seatWH) + seatWH * 2.0f - seatWH / 3f;
                top = rectFWall.bottom + seatWH * 1.5f + i * (seatWH);
            }
        } else if (cabinType == CabinType.Last) {
            if (type == SeatType.Left) {
                left = rectFCabin.left + j * (seatWH) + seatWH / 3;
                top = rectFWC.bottom + seatWH * 1.5f + i * (seatWH);
            } else if (type == SeatType.Middle) {
                left = rectFCabin.left + j * (seatWH) + seatWH * 1f;
                top = rectFWC.bottom + seatWH * 1.5f + i * (seatWH);
            } else if (type == SeatType.Right) {
                left = rectFCabin.left + j * (seatWH) + seatWH * 2.0f - seatWH / 3f;
                top = rectFWC.bottom + seatWH * 1.5f + i * (seatWH);
            }
        }
        RectFloat sRectF = new RectFloat();
        sRectF = new RectFloat(left, top, left + seatWH, top + seatWH);
        PointSeat point = null;
        if (cabinType == CabinType.Frist) {
            point = new PointSeat(i, j);
        } else if (cabinType == CabinType.Second) {
            point = new PointSeat(i + 7, j);
        } else if (cabinType == CabinType.Tourist) {
            point = new PointSeat(i + 10, j);
        } else if (cabinType == CabinType.Last) {
            point = new PointSeat(i + 35, j);
        }

        if (mAnimatedValue == 1) {
            if (cabinType == CabinType.Frist) {
                if (type == SeatType.Left || type == SeatType.Right) {
                    sRectF.top = sRectF.top - rectFCabin.top - rectFCabin.getWidth() / 2
                        - seatWH * (scaleMaxValue - 1.51f) - moveY;
                    sRectF.bottom = sRectF.bottom - rectFCabin.top - rectFCabin.getWidth() / 2
                        - seatWH * (scaleMaxValue - 1.51f) - moveY;
                }
                if (type == SeatType.Middle) {
                    sRectF.top = sRectF.top - rectFCabin.top - rectFCabin.getWidth() / 2
                        - seatWH * (scaleMaxValue - 1.8f) - seatWH / 2f - moveY;
                    sRectF.bottom = sRectF.bottom - rectFCabin.top - rectFCabin.getWidth() / 2
                        - seatWH * (scaleMaxValue - 1.8f) - seatWH / 2f - moveY;
                }
            } else if (cabinType == CabinType.Second) {
                if (type == SeatType.Left || type == SeatType.Right) {
                    sRectF.top = sRectF.top - rectFCabin.top - rectFCabin.getWidth() / 2
                        - seatWH * (scaleMaxValue - 1.25f) - moveY;
                    sRectF.bottom = sRectF.bottom - rectFCabin.top - rectFCabin.getWidth() / 2
                        - seatWH * (scaleMaxValue - 1.25f) - moveY;
                }
                if (type == SeatType.Middle) {
                    sRectF.top = sRectF.top - rectFCabin.top - rectFCabin.getWidth() / 2
                        - seatWH * (scaleMaxValue - 1.75f) - seatWH / 2f - moveY;
                    sRectF.bottom = sRectF.bottom - rectFCabin.top - rectFCabin.getWidth() / 2
                        - seatWH * (scaleMaxValue - 1.75f) - seatWH / 2f - moveY;
                }
            } else if (cabinType == CabinType.Tourist) {
                sRectF.top = sRectF.top - rectFCabin.top - rectFCabin.getWidth() / 2 - seatWH * (scaleMaxValue - 1) - moveY;
                sRectF.bottom = sRectF.bottom - rectFCabin.top - rectFCabin.getWidth() / 2 - seatWH * (scaleMaxValue - 1) - moveY;
            } else if (cabinType == CabinType.Last) {
                sRectF.top = sRectF.top - rectFCabin.top - rectFCabin.getWidth() / 2 - seatWH * (scaleMaxValue - 1) - moveY;
                sRectF.bottom = sRectF.bottom - rectFCabin.top - rectFCabin.getWidth() / 2 - seatWH * (scaleMaxValue - 1) - moveY;
            }

            if (sRectF.top > 0 && sRectF.bottom < getEstimatedHeight()) {
                mSeats.put(getSeatKeyName(point.row, point.column), sRectF);
            }
        }

        if (mSeatSelected.containsKey(getSeatKeyName(point.row, point.column))) {
            canvas.drawPixelMapHolder(new PixelMapHolder(getSeat(seatWH, mSeatSelected.get(getSeatKeyName(point.row, point.column)))), left, top, mPaint);
        } else if (mSeatSelecting.containsKey(getSeatKeyName(point.row, point.column))) {
            canvas.drawPixelMapHolder(new PixelMapHolder(getSeat(seatWH, mSeatSelecting.get(getSeatKeyName(point.row, point.column)))), left, top, mPaint);
            if (mAnimatedValue == 1) {
                if (mSeatSelecting.get(getSeatKeyName(point.row, point.column)) == SeatState.Selecting) {
                    String text = (point.row + 1) + "," + (point.column + 1);
                    mPaintOther.setColor(Color.WHITE);
                    mPaintOther.setTextSize((int) (seatWH / 4f));
                    canvas.drawText(mPaintOther, text, left + seatWH / 2f - getFontlength(mPaintOther, text) / 2,
                        top + seatWH / 2f + getFontHeight(mPaintOther, text) / 3);
                    mPaintOther.setColor(new Color(Color.rgb(138, 138, 138)));
                }
            }
        } else {
            canvas.drawPixelMapHolder(new PixelMapHolder(getSeat(seatWH, SeatState.Normal)), left, top, mPaint);
        }
    }

    private void drawSeatMap(Canvas canvas) {
        if (mAnimatedValue == 1) {
            float mapW = rectFCabin.getWidth() / scaleMap;
            float mapH = (rectFCabin.getHeight() - rectFCabin.getWidth() * 2.5f) / scaleMap + getHeight() / scaleMap;
            RectFloat rectFMap = new RectFloat(rectFCabin.left, rectFCabin.top + rectFCabin.getWidth() * 0.8f + moveY
                , rectFCabin.left + mapW, rectFCabin.top + rectFCabin.getWidth() * 0.8f + mapH + moveY);
            mPaintMap.setColor(new Color(Color.rgb(138, 138, 138)));
            mPaintMap.setAlpha(80f/255f);
            mPaintMap.setStyle(Paint.Style.FILL_STYLE);
            canvas.drawRect(rectFMap, mPaintMap);
            mapH = getHeight() / scaleMap;

            RectFloat rectFMapSee = new RectFloat(rectFCabin.left,
                rectFCabin.top + rectFCabin.getWidth() * 0.8f + moveY + moveY / scaleMap, rectFCabin.left + mapW,
                rectFCabin.top + rectFCabin.getWidth() * 0.8f + mapH + moveY + moveY / scaleMap);
            mPaintMap.setStyle(Paint.Style.STROKE_STYLE);
            mPaintMap.setStrokeWidth(dip2px(0.75f));
            mPaintMap.setColor(Color.RED);
            canvas.drawRect(rectFMapSee, mPaintMap);
            mPaintMap.setStrokeWidth(0);

            if (mSeatSelectingRectF.size() > 0) {
                mPaintMap.setStyle(Paint.Style.FILL_STYLE);
                mPaintMap.setColor(Color.RED);
                mPaintMap.setAlpha(80f/255f);
                RectFloat r = new RectFloat();
                Iterator iter = mSeatSelectingRectF.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String key = (String) entry.getKey();
                    RectFloat val = (RectFloat) entry.getValue();
                    r.top = val.top + moveY;
                    r.bottom = val.bottom + moveY;
                    r.left = val.left - dip2px(0.5f);
                    r.right = val.right - dip2px(0.5f);
                    canvas.drawRect(r, mPaintMap);
                }
            }
        }
    }

    private void drawSeatFirst(Canvas canvas) {
        int row = 7;
        int column = 7;
        mSeats.clear();
        float seatWH = (float) (rectFCabin.getWidth() / 9.0f);
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                if (i >= 0 && j < 2) {
                    setSeat(i, j, canvas, seatWH, SeatType.Left, CabinType.Frist);
                } else if (j >= 2 && j < 5 && i < row - 1) {
                    setSeat(i, j, canvas, seatWH, SeatType.Middle, CabinType.Frist);
                } else if (j >= 5) {
                    setSeat(i, j, canvas, seatWH, SeatType.Right, CabinType.Frist);
                }
            }
        }
        rectFWC.top = rectFCabin.top + rectFCabin.getWidth() / 2 + seatWH + (row + 2.5f) * (seatWH) + seatWH / 2;
        rectFWC.bottom = rectFCabin.top + rectFCabin.getWidth() / 2 + seatWH + (row + 4.5f) * (seatWH) + seatWH / 2;
        rectFWC.left = rectFCabin.left + seatWH / 3;
        rectFWC.right = rectFCabin.left + seatWH / 3 + seatWH * 2;
        mPaintOther.setStyle(Paint.Style.STROKE_STYLE);

        canvas.drawRect(rectFWC, mPaintOther);
        drawWcText(rectFWC, canvas);

        RectFloat rectFWifi = new RectFloat();
        rectFWifi.top = rectFCabin.top + rectFCabin.getWidth() / 2 +
            seatWH + (row + 1f) * (seatWH) + seatWH / 2;
        rectFWifi.bottom = rectFCabin.top + rectFCabin.getWidth() / 2 +
            seatWH + (row + 4.5f) * (seatWH) + seatWH / 2;
        rectFWifi.left = rectFWC.right + seatWH / 2f;
        rectFWifi.right = rectFCabin.left + column * (seatWH) + seatWH * 2f
            - seatWH / 3f - seatWH * 2 - seatWH / 2f;

        canvas.drawRect(rectFWifi, mPaintOther);
        drawWifiLogo(rectFWifi, canvas);

        rectFWC.top = rectFCabin.top + rectFCabin.getWidth() / 2 +
            seatWH + (row + 2.5f) * (seatWH) + seatWH / 2;
        rectFWC.bottom = rectFCabin.top + rectFCabin.getWidth() / 2 +
            seatWH + (row + 4.5f) * (seatWH) + seatWH / 2;
        rectFWC.right = rectFCabin.left + column * (seatWH) + seatWH * 2f
            - seatWH / 3f;
        rectFWC.left = rectFCabin.left + column * (seatWH) + seatWH * 2f
            - seatWH / 3f - seatWH * 2;
        mPaintOther.setStyle(Paint.Style.STROKE_STYLE);

        canvas.drawRect(rectFWC, mPaintOther);
        drawWcText(rectFWC, canvas);
        drawSeatSecond(canvas, seatWH);
    }

    private void drawSeatSecond(Canvas canvas, float seatWH) {
        int row = 3;
        int column = 8;
        float seatWH2 = (float) (rectFCabin.getWidth() / 10.0f);
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                if (i >= 0 && j < 2) {
                    setSeat(i, j, canvas, seatWH2, SeatType.Left, CabinType.Second);
                } else if (j >= 2 && j < 6) {
                    setSeat(i, j, canvas, seatWH2, SeatType.Middle, CabinType.Second);
                } else if (j >= 6) {
                    setSeat(i, j, canvas, seatWH2, SeatType.Right, CabinType.Second);
                }
            }
        }

        mPaintOther.setStyle(Paint.Style.FILL_STYLE);
        rectFWall.top = rectFCabin.top + seatWH * 13 + rectFCabin.getWidth() / 2 + seatWH + (row + 1) * (seatWH2) + seatWH2 / 2;
        rectFWall.left = rectFCabin.left + seatWH2 / 3;
        rectFWall.right = rectFCabin.left + seatWH2 / 3 + 2.5f * seatWH2;
        rectFWall.bottom = rectFCabin.top + seatWH * 13 + rectFCabin.getWidth() / 2 + seatWH + (row + 1) * (seatWH2) + seatWH2 / 2
            + ((int) (dip2px(2) * mAnimatedValue < 1 ? 1 : (int) (dip2px(2) * mAnimatedValue)));

        canvas.drawRoundRect(rectFWall, dip2px(1), dip2px(1), mPaintOther);
        rectFWall.top = rectFCabin.top + seatWH * 13 + rectFCabin.getWidth() / 2 + seatWH + (row + 1) * (seatWH2) + seatWH2 / 2;
        rectFWall.left = rectFCabin.left + column * (seatWH2) + seatWH2 * 2f - seatWH / 3f - 2.5f * seatWH2;
        rectFWall.right = rectFCabin.left + column * (seatWH2) + seatWH2 * 2f - seatWH / 3f;
        rectFWall.bottom = rectFCabin.top + seatWH * 13 + rectFCabin.getWidth() / 2 + seatWH + (row + 1) * (seatWH2) + seatWH2 / 2
            + ((int) (dip2px(2) * mAnimatedValue < 1 ? 1 : (int) (dip2px(2) * mAnimatedValue)));

        canvas.drawRoundRect(rectFWall, dip2px(1), dip2px(1), mPaintOther);
    }

    private void drawSeatTourist(Canvas canvas) {
        int row = 25;
        int column = 10;
        int seatWH = (int) (rectFCabin.getWidth() / 12);
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                if (j >= 0 && j < 3) {
                    setSeat(i, j, canvas, seatWH, SeatType.Left, CabinType.Tourist);
                } else if (j >= 3 && j < 7) {
                    setSeat(i, j, canvas, seatWH, SeatType.Middle, CabinType.Tourist);
                } else if (j >= 7) {
                    setSeat(i, j, canvas, seatWH, SeatType.Right, CabinType.Tourist);
                }
            }
        }
        rectFWC.top = rectFWall.bottom + seatWH * 1.5f + 26 * (seatWH);
        rectFWC.bottom = rectFWC.top + seatWH * 3;
        rectFWC.left = rectFCabin.left + seatWH / 3;
        rectFWC.right = rectFCabin.left + seatWH / 3 + seatWH * 3;
        mPaintOther.setStyle(Paint.Style.STROKE_STYLE);

        canvas.drawRect(rectFWC, mPaintOther);
        drawWcText(rectFWC, canvas);

        RectFloat rectFWifi = new RectFloat();
        rectFWifi.top = rectFWall.bottom + seatWH * 1.5f + 26 * (seatWH);
        rectFWifi.bottom = rectFWifi.top + seatWH * 3;
        rectFWifi.left = rectFWC.right + seatWH / 2f;
        rectFWifi.right = rectFCabin.left + column * (seatWH) + seatWH * 2f
            - seatWH / 3f - seatWH * 3 - seatWH / 2f;

        canvas.drawRect(rectFWifi, mPaintOther);
        drawWifiLogo(rectFWifi, canvas);

        rectFWC.top = rectFWall.bottom + seatWH * 1.5f + 26 * (seatWH);
        rectFWC.bottom = rectFWC.top + seatWH * 3;
        rectFWC.left = rectFCabin.left + column * (seatWH) + seatWH * 2f - seatWH / 3f - seatWH * 3;
        rectFWC.right = rectFCabin.left + column * (seatWH) + seatWH * 2f - seatWH / 3f;
        mPaintOther.setStyle(Paint.Style.STROKE_STYLE);

        canvas.drawRect(rectFWC, mPaintOther);
        drawWcText(rectFWC, canvas);
    }

    private void drawSeatLast(Canvas canvas) {
        int row = 19;
        int column = 10;
        int seatWH = (int) (rectFCabin.getWidth() / 12);
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                if (j >= 0 && j < 3) {
                    setSeat(i, j, canvas, seatWH, SeatType.Left, CabinType.Last);
                } else if (j >= 3 && j < 7) {
                    setSeat(i, j, canvas, seatWH, SeatType.Middle, CabinType.Last);
                } else if (j >= 7) {
                    setSeat(i, j, canvas, seatWH, SeatType.Right, CabinType.Last);
                }
            }
        }
    }

    /**
     * get the path from id
     *
     * @param context the context
     * @param id      the id
     * @return the path from id
     */
    public static String getPathById(Context context, int id) {
        String path = "";
        if (context == null) {
            return path;
        }
        ResourceManager manager = context.getResourceManager();
        if (manager == null) {
            return path;
        }
        try {
            path = manager.getMediaPath(id);
        } catch (IOException e) {
            LogUtil.error(TAG, "IOException occurred " + e.getLocalizedMessage());
        } catch (NotExistException e) {
            LogUtil.error(TAG, "NotExistException occurred " + e.getLocalizedMessage());
        } catch (WrongTypeException e) {
            LogUtil.error(TAG, "WrongTypeException occurred " + e.getLocalizedMessage());
        }
        return path;
    }

    private PixelMap setBitmapSize(int iconId, float w) {
        String path = getPathById(getContext(), iconId);
        RawFileEntry assetManager = getContext().getResourceManager().getRawFileEntry(path);
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        ImageSource.SourceOptions options = new ImageSource.SourceOptions();
        PixelMap pixelMap = null;
        try {
            Resource asset = assetManager.openRawFile();
            ImageSource source = ImageSource.create(asset, options);
            pixelMap = source.createPixelmap(decodingOptions);
        } catch (IOException e) {
            e.getLocalizedMessage();
        }
        float s = w * 1.0f / pixelMap.getImageInfo().size.width;

        PixelMap.InitializationOptions  opts = new PixelMap.InitializationOptions();
        opts.size = new Size((int)(pixelMap.getImageInfo().size.width * s),  (int) (pixelMap.getImageInfo().size.height * s));

        pixelMap = PixelMap.create(pixelMap, opts);
        return  pixelMap;
    }

    private PixelMap getSeat(float getWidth, SeatState type) {
        if (type == SeatState.Normal) {
            if (mBitmapSeat_normal == null) {
                mBitmapSeat_normal = setBitmapSize(ResourceTable.Media_seat_normal, getWidth);
            } else if (Math.abs(mBitmapSeat_normal.getImageInfo().size.width - getWidth) > 1) {
                mBitmapSeat_normal = setBitmapSize(ResourceTable.Media_seat_normal, getWidth);
            }
            return mBitmapSeat_normal;
        }
        if (type == SeatState.Selected) {
            if (mBitmapSeat_selected == null) {
                mBitmapSeat_selected = setBitmapSize(ResourceTable.Media_seat_select, getWidth);
            } else if (Math.abs(mBitmapSeat_selected.getImageInfo().size.width - getWidth) > 1) {
                mBitmapSeat_selected = setBitmapSize(ResourceTable.Media_seat_select, getWidth);
            }
            return mBitmapSeat_selected;
        }
        if (type == SeatState.Selecting) {
            if (mBitmapSeat_selecting == null) {
                mBitmapSeat_selecting = setBitmapSize(ResourceTable.Media_seat_unselect, getWidth);
            } else if (Math.abs(mBitmapSeat_selecting.getImageInfo().size.width - getWidth) > 1) {
                mBitmapSeat_selecting = setBitmapSize(ResourceTable.Media_seat_unselect, getWidth);
            }
            return mBitmapSeat_selecting;
        }
        return null;
    }

    public PixelMap getBitmapFuselage(float rectFCabinWidth) {
        Canvas canvas = null;
        int w = getWidth();
        int h = getHeight();

        if (mBitmapFuselage == null) {
            PixelMap.InitializationOptions opts = new PixelMap.InitializationOptions();
            opts.size = new Size(w, h);
            opts.pixelFormat = PixelFormat.ARGB_8888;
            mBitmapFuselage = PixelMap.create(opts);

            canvas = new Canvas(new Texture(mBitmapFuselage));
            pathFuselage.moveTo(w / 2f - rectFCabinWidth / 2f - dip2px(2),
                rectFCabin.top + rectFCabinWidth / 2f);
            pathFuselage.cubicTo(w / 2f - rectFCabinWidth / 4f, rectFCabin.top - rectFCabinWidth * 1.2f,
                w / 2f + rectFCabinWidth / 4f, rectFCabin.top - rectFCabinWidth * 1.2f,
                w / 2f + rectFCabinWidth / 2f + dip2px(2), rectFCabin.top + rectFCabinWidth / 2f);
            rectFCabin.top = rectFCabin.top + dip2px(10);//机翼向下平移距离
            pathFuselage.lineTo(w / 2f + rectFCabinWidth / 2f + dip2px(2), rectFCabin.top + rectFCabin.getHeight() / 3f);
            pathFuselage.lineTo(w, rectFCabin.top + rectFCabin.getHeight() * 0.55f);
            pathFuselage.lineTo(w, rectFCabin.top + rectFCabin.getHeight() * 0.55f + rectFCabin.getWidth() * 0.8f);
            pathFuselage.lineTo(rectFCabin.right + rectFCabin.getWidth() / 2 * 1.5f, rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f);
            pathFuselage.lineTo(w / 2f + rectFCabinWidth / 2f + dip2px(2), rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f);
            pathFuselage.lineTo(w / 2f + rectFCabinWidth / 2f + dip2px(2), rectFCabin.bottom - rectFCabinWidth / 2f);

            pathFuselage.cubicTo(w / 2f + rectFCabinWidth / 4f,
                rectFCabin.bottom + rectFCabinWidth * 2.5f, w / 2f - rectFCabinWidth / 4f,
                rectFCabin.bottom + rectFCabinWidth * 2.5f, w / 2f - rectFCabinWidth / 2f - dip2px(2), rectFCabin.bottom - rectFCabinWidth / 2f);

            pathFuselage.lineTo(w / 2f - rectFCabinWidth / 2f - dip2px(2), rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f);
            pathFuselage.lineTo(rectFCabin.left - rectFCabin.getWidth() / 2 * 1.5f, rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f);
            pathFuselage.lineTo(0, rectFCabin.top + rectFCabin.getHeight() * 0.55f + rectFCabin.getWidth() * 0.8f);
            pathFuselage.lineTo(0, rectFCabin.top + rectFCabin.getHeight() * 0.55f);
            pathFuselage.lineTo(w / 2f - rectFCabinWidth / 2f - dip2px(2), rectFCabin.top + rectFCabin.getHeight() / 3f);
            pathFuselage.close();
            mPaint.setColor(Color.WHITE);
            mPaint.setAlpha(150f/255f);

            canvas.drawPath(pathFuselage, mPaint);
        }
        return mBitmapFuselage;
    }

    private PixelMap getBitmapCabin() {
        Canvas canvas = null;
        if (mBitmapCabin == null) {
            PixelMap.InitializationOptions opts = new PixelMap.InitializationOptions();
            opts.size = new Size(getWidth(), getHeight());
            opts.pixelFormat = PixelFormat.ARGB_8888;
            mBitmapCabin = PixelMap.create(opts);
            canvas = new Canvas(new Texture(mBitmapCabin));
            mPaint.setColor(Color.WHITE);
            rectFCabin.top = rectFCabin.top - dip2px(10);
            rectFCabin.bottom = rectFCabin.bottom + dip2px(5);
            canvas.drawRoundRect(rectFCabin, getWidth() / 8f / 2f, getWidth() / 8f / 2f, mPaint);
        }
        return mBitmapCabin;
    }

    public PixelMap getBitmapArrow() {
        Canvas canvas = null;
        if (mBitmapArrow == null) {
            PixelMap.InitializationOptions opts = new PixelMap.InitializationOptions();
            opts.size = new Size(getWidth(), getHeight());
            opts.pixelFormat = PixelFormat.ARGB_8888;
            mBitmapArrow = PixelMap.create(opts);
            canvas = new Canvas(new Texture(mBitmapArrow));

            pathArrow.reset();
            pathArrow.moveTo(rectFCabin.right + rectFCabin.getWidth() / 2 * 1.2f, rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f);
            pathArrow.quadTo(rectFCabin.right + rectFCabin.getWidth() / 2 * 1.3f,
                rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 5f,
                rectFCabin.right + rectFCabin.getWidth() / 2 * 1.4f,
                    rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f);

            pathArrow.close();
            canvas.drawPath(pathArrow, mPaint);
            pathArrow.reset();
            pathArrow.moveTo(rectFCabin.left - rectFCabin.getWidth() / 2 * 1.2f, rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f);
            pathArrow.quadTo(rectFCabin.left - rectFCabin.getWidth() / 2 * 1.3f,
                rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 5f,
                rectFCabin.left - rectFCabin.getWidth() / 2 * 1.4f, rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f);

            pathArrow.close();
            canvas.drawPath(pathArrow, mPaint);
            pathArrow.reset();

            float right1x = getWidth();
            float right1y = rectFCabin.top + rectFCabin.getHeight() * 0.55f + rectFCabin.getWidth() * 0.8f;
            float right2x = rectFCabin.right + rectFCabin.getWidth() / 2 * 1.5f;
            float right2y = rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f;
            pathArrow.moveTo((right1x + right2x) / 2f, (right1y + right2y) / 2f);
            pathArrow.quadTo((right1x + right2x) / 2f + rectFCabin.getWidth() / 2 * 0.1f,
                (right1y + right2y) / 2f + rectFCabin.getHeight() / 60f * 7f,
                (right1x + right2x) / 2f + rectFCabin.getWidth() / 2 * 0.2f,
                (right1y + right2y) / 2f);
            canvas.drawPath(pathArrow, mPaint);

            pathArrow.reset();
            float left1x = 0;
            float left1y = rectFCabin.top + rectFCabin.getHeight() * 0.55f + rectFCabin.getWidth() * 0.8f;
            float left2x = rectFCabin.left - rectFCabin.getWidth() / 2 * 1.5f;
            float left2y = rectFCabin.top + rectFCabin.getHeight() / 2f + rectFCabin.getHeight() / 6f / 2f;
            pathArrow.moveTo((left1x + left2x) / 2f, (left1y + left2y) / 2f);
            pathArrow.quadTo((left1x + left2x) / 2f - rectFCabin.getWidth() / 2 * 0.1f,
                (left1y + left2y) / 2f + rectFCabin.getHeight() / 60f * 7f, (left1x + left2x) / 2f - rectFCabin.getWidth() / 2 * 0.2f,
                (left1y + left2y) / 2f);
            mPaint.setColor(Color.WHITE);
            mPaint.setAlpha(150f/255f);
            canvas.drawPath(pathArrow, mPaint);
        }
        return mBitmapArrow;
    }

    private PixelMap getBitmapTail() {
        Canvas canvas = null;
        if (mBitmapTail == null) {
            PixelMap.InitializationOptions opts = new PixelMap.InitializationOptions();
            opts.size = new Size(getWidth(), getHeight());
            opts.pixelFormat = PixelFormat.ARGB_8888;
            mBitmapTail = PixelMap.create(opts);
            canvas = new Canvas(new Texture(mBitmapTail));
            pathTail.reset();
            rectFCabin.bottom = rectFCabin.bottom - dip2px(5);
            pathTail.moveTo(rectFCabin.getCenter().getPointX(),
                rectFCabin.bottom + rectFCabin.getWidth() / 2);
            pathTail.lineTo(rectFCabin.getCenter().getPointX() + rectFCabin.getWidth() * 1.5f,
                rectFCabin.bottom + rectFCabin.getWidth() * 1.5f);
            pathTail.lineTo(rectFCabin.getCenter().getPointX() + rectFCabin.getWidth() * 1.5f,
                rectFCabin.bottom + rectFCabin.getWidth() * 2f);
            pathTail.lineTo(rectFCabin.getCenter().getPointX(),
                rectFCabin.bottom + rectFCabin.getWidth() * 1.5f);
            pathTail.lineTo(rectFCabin.getCenter().getPointX() - rectFCabin.getWidth() * 1.5f,
                rectFCabin.bottom + rectFCabin.getWidth() * 2f);
            pathTail.lineTo(rectFCabin.getCenter().getPointX() - rectFCabin.getWidth() * 1.5f,
                rectFCabin.bottom + rectFCabin.getWidth() * 1.5f);
            pathTail.close();

            canvas.drawPath(pathTail, mPaint);
            pathTail.reset();
            pathTail.moveTo(rectFCabin.getCenter().getPointX() - rectFCabin.getWidth() / 2 * 0.1f,
                rectFCabin.bottom + rectFCabin.getWidth() * 1.5f);
            pathTail.quadTo(
                rectFCabin.getCenter().getPointX(),
                rectFCabin.bottom + rectFCabin.getWidth() * 3f,
                rectFCabin.getCenter().getPointX() + rectFCabin.getWidth() / 2 * 0.1f,
                rectFCabin.bottom + rectFCabin.getWidth() * 1.5f);
            pathTail.close();
            mPaint.setColor(Color.WHITE);
            mPaint.setAlpha(150f/255f);
            canvas.drawPath(pathTail, mPaint);
        }
        return mBitmapTail;
    }

    public void startAnim(boolean zoomOut) {// false zoom in,true zoom out
        startViewAnim(0f, 1f, 280, zoomOut);
    }

    private AnimatorValue valueAnimator;
    private float mAnimatedValue = 0f;

    public void stopAnim() {
        if (valueAnimator != null) {
            clearFocus();
            valueAnimator.setLoopedCount(0);
            valueAnimator.stop();
            valueAnimator.cancel();
            valueAnimator.end();
            mAnimatedValue = 0f;
            invalidate();
        }
    }

    private AnimatorValue startViewAnim(float startF, final float endF, long time, final boolean zoomOut) {
        if (zoomOut && moveY > 0) {
            moveY = 0;
            invalidate();
        }
        if (zoomOut) {
            mAnimatedValue = 1 - mAnimatedValue;
        }
        invalidate();

        valueAnimator = new AnimatorValue();
        valueAnimator.setCurveType(Animator.CurveType.LINEAR);
        valueAnimator.setDuration(time);
        if (!valueAnimator.isRunning()) {
            valueAnimator.start();
        }
        return valueAnimator;
    }

    public float getFontlength(Paint paint, String str) {
        Rect rect = new Rect();
        paint.getTextBounds(str);
        return rect.getWidth();
    }

    public float getFontHeight(Paint paint, String str) {
        Rect rect = new Rect();
        paint.getTextBounds(str);
        return rect.getHeight();
    }

    public class PointSeat {
        public int row;
        public int column;
        public PointSeat(int row, int column) {
            this.row = row;
            this.column = column;
        }
    }

    private void drawWcText(RectFloat rectFWC, Canvas canvas) {
        mPaintOther.setTextSize((int) (rectFWC.getWidth() / 4));
        mPaintOther.setAlpha(150f/255f);
        canvas.drawText(mPaintOther, "WC",
            rectFWC.getCenter().getPointX() - getFontlength(mPaintOther, "WC") / 2f,
            rectFWC.getCenter().getPointY() + getFontHeight(mPaintOther, "WC") / 3f);
        mPaintOther.setAlpha(255f/255f);
    }

    private void drawWifiLogo(RectFloat rectFWifi, Canvas canvas) {
        float signalRadius = rectFWifi.getHeight() / 2 / 4;
        RectFloat rect = null;
        mPaintOther.setStrokeWidth(signalRadius / 4);
        mPaintOther.setAlpha(150f/255f);
        float marginTop = signalRadius * (3 + 0.5f) / 2f;

        for (int i = 0; i < 4; i++) {
            float radius = signalRadius * (i + 0.5f);
            if (i == 0) {
                radius = signalRadius / 2f;
            }
            rect = new RectFloat(
                rectFWifi.getCenter().getPointX() - radius,
                rectFWifi.getCenter().getPointY() - radius + marginTop,
                rectFWifi.getCenter().getPointX() + radius,
                rectFWifi.getCenter().getPointY() + radius + marginTop);
            if (i != 0) {
                mPaintOther.setStyle(Paint.Style.STROKE_STYLE);
                canvas.drawArc(rect, new Arc(-135, 90, false), mPaintOther);
            } else {
                mPaintOther.setStyle(Paint.Style.FILL_STYLE);
                canvas.drawArc(rect, new Arc(-135, 90, true), mPaintOther);
            }
        }
        mPaintOther.setStrokeWidth(0);
        mPaintOther.setAlpha(255f/255f);
    }

    @Override
    public void onComponentBoundToWindow(Component component) {}

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        stopAnim();
    }
}
